/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/

#ifndef _TGIMI_PROTOCOL_GRID_H_
#define _TGIMI_PROTOCOL_GRID_H_

#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#define GRID_FORMAT_TYPE_UCHAR 0
#define GRID_FORMAT_TYPE_FLOAT 1

struct TGIMI_PROTOCOL_GRID_HEADER{
		public:
				int32_t t_sec;   ///< Time stamp seconds since epoch
				int32_t t_usec;  ///< Time stamp useconds since epoch
				int32_t size;    ///< The size of grid data in bytes
				int32_t Nx;      ///< The number of elements in x
				int32_t Ny;      ///< The number of elements in y
				float resolution;///< size of one cell in meters
				float x;         ///< The global position of the grid origin
				float y;         ///< The global position of the grid origin
				float a;         ///< The global position of the grid origin
				int32_t orig_x;  ///< The placement of the grid origin within the grid
				int32_t orig_y;  ///< The placement of the grid origin within the grid
				unsigned char format;	///< The format of the grid data (GRID_FORMAT_TYPE_XXX)

				TGIMI_PROTOCOL_GRID_HEADER(){
						setDefaults();
				}
				void setDefaults(){
						t_sec=0; t_usec=0;
						size = 0;
						Nx = 0;
						Ny = 0;
						resolution = 0;
						x=0;y=0;a=0;
						orig_x = 0; orig_y=0;
						format = 0;
				}
};

#define TGIMI_PROTOCOL_GRID_HEADER_SIZE (11*4+1)

struct TGIMI_PROTOCOL_GRID{
		public:
				TGIMI_PROTOCOL_GRID_HEADER *head;
				unsigned char *grid;

				TGIMI_PROTOCOL_GRID():
					head(NULL),
					grid(NULL),
					dataBufferSize(0),
					data(NULL)
				{	}
					~TGIMI_PROTOCOL_GRID(){
							if(data) free(data);
					}


					/**
					* Set grid to packet
					* @p *gr the grid data
					* @p g_size The size of grid in bytes
					* @p g_Nx the number of cells in x-dir
					* @p g_Ny the number of cells in y-dir
					* @p g_resolution the size of one cell in meters
					* @p g_format the format of the grid_data
					*/
					void setGrid(unsigned char *gr,
											 int32_t g_size, int32_t g_Nx,
											 int32_t g_Ny, float g_resolution,
											 unsigned char g_format)
					{
						allocate(g_size);
						copyGrid(gr,g_size);
						head->setDefaults();
						head->size = g_size;
						head->Nx = g_Nx;
						head->Ny = g_Ny;
						head->resolution = g_resolution;
						head->format = g_format;
					}
					/**
					 * Set grid to packet with time stamp
					 *
					 */
					void setGrid(unsigned char *gr,
											 int32_t g_size, int32_t g_Nx,
											 int32_t g_Ny, float g_resolution,
											 unsigned char g_format,
											int32_t sec, int32_t usec)
					{
							setGrid(gr,g_size, g_Nx,g_Ny,g_resolution,g_format);
							head->t_sec = sec;
							head->t_usec = usec;
					}
					/**
					* Set griddata with all header items
					**/
					void setGrid(unsigned char *gr,
											 int32_t g_size, int32_t g_Nx,
											 int32_t g_Ny, float g_resolution,
											 unsigned char g_format,
											 int32_t sec, int32_t usec,
											float g_x, float g_y, float g_a,
											int32_t or_x, int32_t or_y)
					{
							setGrid(gr,g_size, g_Nx,g_Ny,g_resolution,g_format,sec,usec);
							head->x = g_x;
							head->y = g_y;
							head->a = g_a;
							head->orig_x = or_x;
							head->orig_y = or_y;
					}

					void setGrid(unsigned char *gr, TGIMI_PROTOCOL_GRID_HEADER hdr){
							allocate(hdr.size);
							copyGrid(gr,hdr.size);
							memcpy(head,&hdr,TGIMI_PROTOCOL_GRID_HEADER_SIZE);
					}

					/**
					 * Copies the data from the GIMI properly to the structure
					 */
					void handleNetPacket(const unsigned char *indata, int inDataSize){
							TGIMI_PROTOCOL_GRID_HEADER *hdr =
											(TGIMI_PROTOCOL_GRID_HEADER *) indata;

							assert(inDataSize>=TGIMI_PROTOCOL_GRID_HEADER_SIZE);

							assert((hdr->size+TGIMI_PROTOCOL_GRID_HEADER_SIZE) ==  inDataSize);

							allocate(hdr->size);
							memcpy(data, indata, hdr->size+TGIMI_PROTOCOL_GRID_HEADER_SIZE);
					}

						/**
					 * Returns the size of the whole data in bytes
						 */
					int size(){
							if(data)
								return (TGIMI_PROTOCOL_GRID_HEADER_SIZE + head->size);
							else
									return 0;
					}
				/**
				 * Returns pointer to the whole data
				*/
					const unsigned char * getNetPacket(){
							return data;
					}

				/**
				 * Returns A Copy of the header
				*/
					TGIMI_PROTOCOL_GRID_HEADER getHeader(){
						 TGIMI_PROTOCOL_GRID_HEADER hdr;
							if(head){
									memcpy(&hdr,head,TGIMI_PROTOCOL_GRID_HEADER_SIZE);
							}
							return hdr;
					}


		private:
				int32_t dataBufferSize;	///< size of memory reserved for the *data
				unsigned char *data;	///< The whole data

				/*
				* reserves the *data
				*/
				void allocate(int32_t grid_datasize){
						if (dataBufferSize < (grid_datasize+TGIMI_PROTOCOL_GRID_HEADER_SIZE)) {
								if (data) free(data);

								data = (unsigned char *)
												malloc( sizeof(unsigned char)*grid_datasize +
												TGIMI_PROTOCOL_GRID_HEADER_SIZE);

								head = (TGIMI_PROTOCOL_GRID_HEADER *) data;
								grid = (unsigned char *) (head+1);
								dataBufferSize = grid_datasize + TGIMI_PROTOCOL_GRID_HEADER_SIZE;
						}
				}
				void copyGrid(unsigned char *g_data,int32_t g_data_size){
						memcpy(grid, g_data, g_data_size);
				}

};


#endif




